﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Prism.Regions;
using System.Windows;
using System.Collections.Specialized;

namespace Tanmia.Basis.Prism
{
    public class WindowRegionBehavior : IRegionBehavior
    {
        private readonly WeakReference ownerWeakReference;
        private WeakReference regionWeakReference;
        private readonly Style windowStyle;

        public WindowRegionBehavior(Window owner, Style windowStyle)
        {
            ownerWeakReference = new WeakReference(owner);
            this.windowStyle = windowStyle;
        }

        #region IRegionBehavior Members

        public void Attach()
        {
            IRegion region = regionWeakReference.Target as IRegion;

            if (region != null)
            {
                region.Views.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Views_CollectionChanged);
                region.ActiveViews.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ActiveViews_CollectionChanged);
            }
        }

        public IRegion Region
        {
            get { return regionWeakReference.Target as IRegion; }
            set { regionWeakReference = new WeakReference(value); }
        }

        #endregion

        public void Detach()
        {
            IRegion region = regionWeakReference.Target as IRegion;

            if (region != null)
            {
                region.Views.CollectionChanged -= Views_CollectionChanged;
                region.ActiveViews.CollectionChanged -= ActiveViews_CollectionChanged;
            }
        }

        private void ActiveViews_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Window owner = ownerWeakReference.Target as Window;

            if (owner == null)
            {
                Detach();
                return;
            }

            if (e.Action == NotifyCollectionChangedAction.Add)
                foreach (object view in e.NewItems)
                {
                    Window window = GetContainerWindow(owner, view);

                    if (window != null && !window.IsFocused)
                    {
                        window.WindowState = WindowState.Normal;
                        window.Activate();
                    }
                }
        }

        private void Views_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Window owner = ownerWeakReference.Target as Window;

            if (owner == null)
            {
                Detach();
                return;
            }

            if (e.Action == NotifyCollectionChangedAction.Add)
                foreach (object view in e.NewItems)
                {
                    BaseWindow window = new BaseWindow();
                    FrameworkElement fe = view as FrameworkElement;

                    window.Activated += new EventHandler(window_Activated);
                    window.Deactivated += new EventHandler(window_Deactivated);
                    if (this.windowStyle != null)
                        window.Style = this.windowStyle;
                    window.Height = fe.Height + 80;
                    window.Content = view;
                    window.DataContext = fe.DataContext;
                    window.Closed += new EventHandler(window_Closed);
                    window.Owner = owner;
                    window.Show();
                }
            else if (e.Action == NotifyCollectionChangedAction.Remove)
                foreach (object view in e.OldItems)
                {
                    BaseWindow window = GetContainerWindow(owner, view);

                    if (window != null)
                    {
                        window.Close();
                        window.Content = null;
                    }
                }
        }

        private BaseWindow GetContainerWindow(Window owner, object view)
        {
            foreach (Window window in owner.OwnedWindows)
                if (window.Content == view)
                    return window as BaseWindow;

            return null;
        }

        private void window_Closed(object sender, EventArgs e)
        {
            BaseWindow window = sender as BaseWindow;
            IRegion region = regionWeakReference.Target as IRegion;

            if (window != null && region != null)
                if (region.Views.Contains(window.Content))
                {
                    region.Remove(window.Content);
                    window.Content = null;
                }
        }

        private void window_Deactivated(object sender, EventArgs e)
        {
            BaseWindow window = sender as BaseWindow;
            IRegion region = regionWeakReference.Target as IRegion;

            if (window != null && region != null)
                region.Deactivate(window.Content);
        }

        private void window_Activated(object sender, EventArgs e)
        {
            IRegion region = regionWeakReference.Target as IRegion;
            BaseWindow window = sender as BaseWindow;

            if (window != null && !region.ActiveViews.Contains(window.Content))
                region.Activate(window.Content);
        }
    }
}
